package gti310.tp3.parser;

import java.io.BufferedReader;
import java.io.FileReader;

/**
 * La classe ConcreteParser implémente l'interface Parser qui contient la
 * méthode parse servant à interpréter un fichier texte d'entrée et retourne un
 * objet de type E. La classe contient une méthode de validation des données du
 * fichier source et une méthode pour l'analyse des données. 
 * 
 * @author Fredy A. Bonilla et Emile Robinson
 * @param <E> object de type E pour enregistrer les donnéés.
 */
public class ConcreteParser implements Parser<E>{
	
	private E extractedFile;
	private int[] tab = new int[3];
	private boolean termine=false;

	/**
	 * Constructeur de classe par default. 
	 */
	public ConcreteParser(){};

	/**
	 * The parse method is designed to scan an input file and produce an output
	 * object defined by the <E> templace. The method should return null if the
	 * file cannot be read, or if the file structure is different than what is
	 * awaited.
	 * 
	 * @param filename The complete path to the file to parse.
	 * @return E, an object produced from the input file, or null if something
	 * 		   went wrong.
	 */
	public E parse(String filename) {

		extractedFile =  new E();
		String [] fichier = new String[100];
		boolean valide = true;

		try{

			//Création d'un objet de type FilrReader utilisant comme paramètre le
			//nom du fichier source.
			FileReader inputFile = new FileReader(filename);

			//Instance créée de BufferedReader pour parcourir le contenu
			BufferedReader bufferReader = new BufferedReader(inputFile);

			//Variable pour retenir la ligne actuelle
			String line;

			//Compteur
			int buffer = 0;

			/*
			 * Lecture du fichier ligne par ligne et verification du contenu.
			 * La boucle se termine à la détection du caractère "$" dans le
			 * fichier. La méthode validerFichier s'occupe de la validation.
			 */
			while(valide && !termine){
				line = bufferReader.readLine();
				
				if(validerFichier(line,buffer)){
					fichier[buffer] = line;
					buffer++;
				}
				else{
					System.out.println("Toute les lignes du fichier ne sont pas valide");
					extractedFile = null;
					valide = false;	
				}		
			}

			//Fermeture du fichier. 
			bufferReader.close();
			
		}catch(Exception e){
			System.out.println("Error while reading file line by line:" 
					+ e.getMessage());      
			return null;
		}
		
		

		return extractedFile;
	}

	/**
	 * La méthode validerFichier a pour but de valider les données attendues 
	 * dans le fichier source. Elle utilise des regex pour verifier la pésence
	 * des entiers. 
	 * 
	 * @param line, la ligne actuelle du fichier.
	 * @return un boolean validation des données du fichier
	 */
	private boolean validerFichier(String line, int indexLine){

		boolean validated = false;

		//Verifier les trois premieres lignes
		if(line.length() <= 2){

			/*
			 * Validation qu'il s'agit d'entiers seulement. Si c'est le cas,
			 * validated devient TRUE et on procède à l'extraction de données
			 * vers l'object E. 
			 */
			if(line.matches(".*\\d.*")){
				validated = true;
				extractionDonnee(line,indexLine);
			}
			//Validation de la fin du fichier, validated reste false
			else if(line.contains("$")){
				System.out.println("Fin de la validation du fichier");
				validated = true;
				termine = true;
			}
		}
		/*
		 * Vérification que les données soient sous le format suivant:
		 * <source(int)><tabulation><destination(int)><tabluation><poids(int)>
		 */
		else{
			/*
			 * Vérifier si la ligne contient des entiers et des tabulations. Si
			 * c'est le cas, validated devient TRUE et on procède à l'extraction
			 * des données vers l'objet E.  
			 */
			if(line.matches("[a-zA-Z ]*\\d+.*") && line.contains("\t")){
				validated = true;
				extractionDonnee(line,indexLine);
			}
			else
				validated = false;
		}

		return validated;
	}

	/**
	 * Cette méthode permet d'extraire les données nécessaire de la ligne du
	 * fichier source pour obtenir la source, la destination et le poids. Une
	 * fois ce processus complété, les données seront enregistrées dans la 
	 * prévue à cet effet. 
	 * 
	 * @param line, la ligne de donnée à analyser. 
	 * @param l'index de la ligne
	 */
	private void extractionDonnee(String line, int index){
		
		//Vérification qu'il s'agit des trois premiere lignes à un seul entier
		if(line.length() <= 2){
			
			tab[index] = Integer.parseInt(line);
			//Fin des trois première lignes.
			if(index == 2){
				 
				/*
				 * Enregistrement des informations suivantes:
				 * <nombre de sommets><valeur pour l’infinie><sommet de départ>
				 */
				extractedFile.setNbrSommets(tab[index-2]);
				extractedFile.setValeurInfinie(tab[index-1]);
				extractedFile.setSommetDepart(tab[index]);
				
			} //fin du if imbriqué
		} //fin du if principal
		else{
			//Dans le cas qu'il n'y ai pas de sommet de depart fournis
			if(index == 2){
				extractedFile.setNbrSommets(tab[index-2]);
				extractedFile.setValeurInfinie(tab[index-1]);
				extractedFile.setSommetDepart(1); //valeur par défault : 1
			}
			
			String[] tab2 = new String [3];
			
			//Séparation de la chaîne de charactère par les tabulations
			tab2 = line.split("\\t");
			
			//Creation d'une innerListe pour ajouter les 3 information de la ligne
			extractedFile.createInnerList();
			
			/*
			 * Enregistrement des informations suivantes:
			 * <sommet><destination><poids>
			 */
			for(int i=0; i<tab2.length; i++){
				extractedFile.ajouterElementInner(Integer.parseInt(tab2[i]));
			}
			
		}
	}

}
